package com.hmdp.config;

import com.github.shyiko.mysql.binlog.BinaryLogClient;
import com.github.shyiko.mysql.binlog.event.*;
import com.hmdp.entity.patient;
import com.hmdp.service.impl.PatientServiceImpl;
import com.hmdp.utils.PatientUnit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;


@Component
@Slf4j
public class MysqlBinLogClient implements ApplicationRunner {

    int flag = 10;

    private static final String dataBase = "madical";

    private static final String patient = "patient";

    private static final String record = "record";

    private static final String generahealth = "generahealth";

    @Resource
    private PatientServiceImpl patientService;


    @Override
    public void run(ApplicationArguments args) throws Exception {
        //项目启动完成连接bin-log
        new Thread(() -> {
            try {
                connectMysqlBinLog();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
        }).start();

    }

    public void connectMysqlBinLog() throws UnknownHostException {
        log.info(("监控BinLog服务已启动"));
        //自己MySQL的信息。host，port，username，password
        BinaryLogClient client = new BinaryLogClient("127.0.0.1", 3306, "root", "191224");
        /**因为binlog不是以数据库为单位划分的，所以监控binglog不是监控的单个的数据库，而是整个当前所设置连接的MySQL，
         *其中任何一个库发生数据增删改，这里都能检测到，
         *所以不用设置所监控的数据库的名字(我也不知道怎么设置，没发现有包含这个形参的构造函数)
         *如果需要只监控指定的数据库，可以看后面代码，可以获取到当前发生变更的数据库名称。可以根据名称来决定是否监控
         **/

        //client.setServerId(100); //和自己之前设置的server-id保持一致，但是我不知道为什么不一致也能成功

//下面直接照抄就行
        client.registerEventListener(event -> {
                EventData eventData = event.getData();
                if(eventData instanceof TableMapEventData){
                    TableMapEventData tableMapEventData = (TableMapEventData) eventData;
                    String databaseName = tableMapEventData.getDatabase();
                    String tableName = tableMapEventData.getTable();
                    System.out.println("变动的数据库"+databaseName);
                    System.out.println("变动的表"+tableName);
                    if (dataBase.equals(databaseName) && patient.equals(tableName)){
                        flag = 0;
                    }else if(dataBase.equals(databaseName) && record.equals(tableName)){
                        flag = 1;
                    }else if(dataBase.equals(databaseName) && generahealth.equals(tableName)){
                        flag = 2;
                    }
                }
                if (eventData instanceof WriteRowsEventData) {
                    System.out.println("插入操作...........");
                    WriteRowsEventData writeRowsEventData = (WriteRowsEventData) eventData;
                        //病人基本信息插入操作
                        if (flag==0) {
                            // 插入 patient 表的处理逻辑
                            System.out.println("进入操作插入处理");
                            PaientInsert(writeRowsEventData);
                            flag = 10;  //改完恢复，以免再次进入

                            //病人身体指标插入操作
                        } else if (flag==1) {
                            // 修改 record 表的处理逻辑

                            // ...
                            //病人不重要信息的插入操作
                        } else if (flag==2) {
                            // 删除 generahealth 表的处理逻辑
                            // ...
                        }
            } else if (eventData instanceof UpdateRowsEventData) {
                System.out.println("Update:");
                UpdateRowsEventData updateRowsEventData = (UpdateRowsEventData)eventData;
                // 更新操作的处理逻辑
                    // 删除操作的处理逻辑
                    if (flag==0) {
                        // 插入 patient 表的处理逻辑
                        System.out.println("进入修改操作处理");
                        PaientUpdate(updateRowsEventData);
                        flag = 10;  //改完恢复，以免再次进入
                    } else if (flag==1) {
                        // 修改 record 表的处理逻辑

                        // ...
                    } else if (flag==2) {
                        // 删除 generahealth 表的处理逻辑
                        // ...
                    }
                // ...
            } else if (eventData instanceof DeleteRowsEventData) {
                System.out.println("删除操作:");
                DeleteRowsEventData deleteRowsEventData = (DeleteRowsEventData)eventData;
                // 删除操作的处理逻辑
                    if (flag==0) {
                        // 插入 patient 表的处理逻辑
                        System.out.println("进入删除操作处理");
                        PaientDelete(deleteRowsEventData);
                        flag = 10;  //改完恢复，以免再次进入
                    } else if (flag==1) {
                        // 修改 record 表的处理逻辑

                        // ...
                    } else if (flag==2) {
                        // 删除 generahealth 表的处理逻辑
                        // ...
                    }
            }else{
                    return;
                }
        });


        try {
            client.connect();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //病人插入操作的处理
    public void PaientInsert(WriteRowsEventData data){

        System.out.println("进入该函数........");
        List<Serializable[]> rows = data.getRows();
        for (Serializable[] row : rows){
            System.out.println(row);
            Long patientid = (Long) row[0];
            System.out.println(patientid);
            String name  = (String)row[1];
            Long phone = (Long)row[2];
            String password = (String) row[3];
            int type = (int)row[4];
            String publickey = (String)row[5];
            String privatekey = (String) row[6];
            patient p = new patient();
            p.setPatientId(patientid);
            p.setName(name);
            p.setPhone(phone);
            p.setPassword(password);
            p.setType(type);
            p.setPublickey(publickey);
            p.setPrivatekey(privatekey);
            System.out.println("插入的患者数据："+p.toString());
            patientService.insert(p,"insert");
        }
    }


    //病人删除操作的处理
    public void PaientDelete(DeleteRowsEventData data) {
        System.out.println("进入该函数........");
        List<Serializable[]> rows = data.getRows();
        for (Serializable[] row : rows) {
            System.out.println(row);
            Long patientid = (Long) row[0];
            System.out.println(patientid);
            String name = (String) row[1];
            Long phone = (Long) row[2];
            String password = (String) row[3];
            int type = (int) row[4];
            String publickey = (String) row[5];
            String privatekey = (String) row[6];
            patient p = new patient();
            p.setPatientId(patientid);
            p.setName(name);
            p.setPhone(phone);
            p.setPassword(password);
            p.setType(type);
            p.setPublickey(publickey);
            p.setPrivatekey(privatekey);
            System.out.println("删除的患者数据：" + p.toString());
            patientService.insert(p,"delete");
        }
    }

    //修改操作
    public  void PaientUpdate(UpdateRowsEventData data){
        // 获取修改前后的数据
        List<Map.Entry<Serializable[], Serializable[]>> rows = data.getRows();
        for (Map.Entry<Serializable[], Serializable[]> row : rows) {
            // 修改前的数据
            Serializable[] oldData = row.getKey();
            // 修改后的数据
            Serializable[] newData = row.getValue();
            // 处理修改前后的数据
            processData(oldData, newData);
        }
    }

    public void processData(Serializable[] oldData, Serializable[] newData) {
        // 在这里处理修改前后的数据
        // 可以将数据保存到本地、发送到其他系统或执行其他操作
        // ...
        Long oldPatientId = (Long) oldData[0];
        String OldName = (String) oldData[1];
        Long OldPhone = (Long) oldData[2];
        String OldPhoneStr =String.valueOf(OldPhone);
        String OldPassword = (String) oldData[3];
        int OldType = (int) oldData[4];
        String OldTypeStr =String.valueOf(OldType);
        Long NewPatientId = (Long) newData[0];
        String NewName = (String) newData[1];
        Long NewPhone = (Long) newData[2];
        String NewPhoneStr =String.valueOf(NewPhone);
        String NewPassword = (String) newData[3];
        int NewType = (int) newData[4];
        String NewTypeStr =String.valueOf(NewType);

        String name = "旧: "+OldName+"新： "+NewName;
        String phone = "旧: "+OldPhoneStr+"新： "+NewPhoneStr;
        String password = "旧： "+OldPassword+"新: "+NewPassword;
        String type = "旧: "+OldTypeStr+"新： "+NewTypeStr;
        PatientUnit patientUnit = new PatientUnit(oldPatientId,name,phone,password,type);
        patientService.updatePatient(patientUnit,NewType);


    }


    //病人的修改操作

}

